<!DOCTYPE html><html><head><title>单页面应用和多页面应用</title><meta charset='utf-8'><link href='https://cdn.maxiang.io/res-min/themes/marxico.css' rel='stylesheet'><style>
.note-content  {font-family: 'Helvetica Neue', Arial, 'Hiragino Sans GB', STHeiti, 'Microsoft YaHei', 'WenQuanYi Micro Hei', SimSun, Song, sans-serif;}

</style></head><body><div id='preview-contents' class='note-content'>
                        
                    



<h2 id="单页面应用和多页面应用">单页面应用和多页面应用</h2>

<p></p>

<blockquote>
  <p>SPA：single page web application 单页面WEB应用（一个产品只有一个页面，所有内容的展示和业务的处理都是在这个页面完成的）</p>
  
  <p>MPA：multi page web application 多页面WEB应用（一个产品包含很多页面，通过页面之前的跳转完成业务逻辑的衔接等）</p>
</blockquote>



<h3 id="spa单页面应用的发展历程">SPA单页面应用的发展历程</h3>

<p>1、页面是基于服务器端渲染的，不管是多页面还是单页面，我们肯定有很多需要公共使用的部分，此时我们把它封装成一个组件，通过相关的技术导入到具体的某一个页面中（例如：include…）</p>

<p>2、基于IFRAME完成SPA单页面应用开发（前端负责）</p>

<blockquote>
  <p>优势：主体页面内容依然是一个个的单独开发的，页面加载的时候，只渲染部分页面内容，想要展示谁，才去加载谁（性能上还是不错的）</p>
  
  <p>弊端：父子页面之间的信息通信（包括一些公共资源的使用）IFRAME都体现的不是特别良好</p>
</blockquote>

<p>3、基于轻量级框架的模块化开发</p>

<blockquote>
  <p>AMD：require.js</p>
  
  <p>CMD：sea.js</p>
  
  <p>自动化平台：grunt\gulp\fis</p>
</blockquote>

<p>开发很多的模块，后期基于gulp把所有的模块合并在一起（合并到一个页面中）</p>

<blockquote>
  <p>优势：单纯一个页面，不存在跨页面这一说，模块之间的信息通信以及公共资源的使用都展现良好</p>
  
  <p>弊端：合并后的页面，需要加载大量的资源，首次加载速度慢（也可以解决，一般都是基于HASH解决的，不过需要额外的处理）</p>
</blockquote>

<p>4、VUE/REACT中的路由管理，基于路由实现单页面应用(即解决了资源共享和信息通信问题，也考虑了性能优化，按需加载所需的资和内容…)</p>



<h3 id="spa和mpa的对比">SPA和MPA的对比</h3>



<p><img longdesc="./1530032181910.png" alt="Alt text" title="" type="image/png" src="" class=""></p>



<h3 id="react-router-dom-实现spa单页面应用">react-router-dom 实现SPA单页面应用</h3>

<blockquote>
  <p>$ yarn add react-router-dom</p>
</blockquote>

<p>学习的API： <br>
<a href="http://react-guide.github.io/react-router-cn/docs/API.html" target="_blank">http://react-guide.github.io/react-router-cn/docs/API.html</a></p>

<p><strong>基础使用</strong></p>



<pre class="prettyprint hljs-light"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> {HashRouter, Route} <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">/*</span>
</div><div class="hljs-line"><span class="hljs-comment"> * REACT-ROUTER中提供了两种路由方式：</span>
</div><div class="hljs-line"><span class="hljs-comment"> *   1、BROWSER-ROUTER (基于H5中的HISTORY-API完成的)</span>
</div><div class="hljs-line"><span class="hljs-comment"> *     http://www.xxx.com/user</span>
</div><div class="hljs-line"><span class="hljs-comment"> *     http://www.xxx.com/user/singin</span>
</div><div class="hljs-line"><span class="hljs-comment"> *</span>
</div><div class="hljs-line"><span class="hljs-comment"> *   2、HASH-ROUTER （基于HASH值处理）</span>
</div><div class="hljs-line"><span class="hljs-comment"> *     http://www.xxx.com/#/user</span>
</div><div class="hljs-line"><span class="hljs-comment"> *     http://www.xxx.com/#/user/singin</span>
</div><div class="hljs-line"><span class="hljs-comment"> *</span>
</div><div class="hljs-line"><span class="hljs-comment"> *   如果项目是单纯静态页面展示(数据绑定是有客户端完成的)，一般我们都使用HASH-ROUTER完成；如果当前的项目有些内容是需要后台完成，我们尽量使用BROWSER-ROUTER，因为HASH值不太容易和服务器端产生关联；</span>
</div><div class="hljs-line"><span class="hljs-comment"> *</span>
</div><div class="hljs-line"><span class="hljs-comment"> * ------------------</span>
</div><div class="hljs-line"><span class="hljs-comment"> *</span>
</div><div class="hljs-line"><span class="hljs-comment"> * 每一个ROUTER(HASH-ROUTER或者BROWSER-ROUTER)都只能有一个子元素，我们需要把我们配置的每一条规则(ROUTE)放到一个容器中</span>
</div><div class="hljs-line"><span class="hljs-comment"> */</span>
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> A <span class="hljs-keyword">from</span> <span class="hljs-string">'./component/A'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> B <span class="hljs-keyword">from</span> <span class="hljs-string">'./component/B'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> C <span class="hljs-keyword">from</span> <span class="hljs-string">'./component/C'</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">ReactDOM.render(&lt;HashRouter&gt;
</div><div class="hljs-line">    &lt;div&gt;
</div><div class="hljs-line">        {/*
</div><div class="hljs-line">          * path:当前请求的路径(指的是HASH值后的内容)
</div><div class="hljs-line">          * component:符合当前路径后渲染的组件
</div><div class="hljs-line">          * render:符合当前路径后执行的渲染方法(方法中可以根据自己的需求返回不同的组件或者内容,用来最后渲染)
</div><div class="hljs-line">          * exact
</div><div class="hljs-line">          * strict
</div><div class="hljs-line">          *
</div><div class="hljs-line">          * 默认情况下，只要PATH='/'，基本上所有请求的路径都可以把它匹配了，而这种路径一般都是首页的路径，我们如何控制，只有路径是一个斜杠才匹配，只要后面再有其它内容，就让其不匹配?
</div><div class="hljs-line">          * =&gt;使用ROUTE中的EXACT来处理:准确精准的来匹配
</div><div class="hljs-line">          */}
</div><div class="hljs-line">        &lt;Route path='/' exact component={A}/&gt;
</div><div class="hljs-line">        &lt;Route path='/user' render={() =&gt; {
</div><div class="hljs-line">            //=&gt;基于RENDER一般都是做路由权限校验
</div><div class="hljs-line">            let loginInfo = localStorage.getItem('login-info');
</div><div class="hljs-line">            if (!loginInfo) {
</div><div class="hljs-line">                return &lt;div&gt;暂时未登录&lt;/div&gt;;
</div><div class="hljs-line">            }
</div><div class="hljs-line">            return &lt;B/&gt;;
</div><div class="hljs-line">        }}/&gt;
</div><div class="hljs-line">        &lt;Route path='/user/singin' component={C}/&gt;
</div><div class="hljs-line">    &lt;/div&gt;
</div><div class="hljs-line">&lt;/HashRouter&gt;, window.root);
</div></code></pre>

<p><strong>搭建客户管理系统</strong></p>



<pre class="prettyprint hljs-light"><code class="hljs 1c"><div class="hljs-line">/*
</div><div class="hljs-line"> * 基于REACT的ROUTER实现SPA单页面应用,我们会按照如下的工程目录开发：
</div><div class="hljs-line"> *  <span class="hljs-string">|-SRC</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|--component 存放的是各个组件(组件:可被公共使用的)</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|--container(routers) 这里一般存放的是页面</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|----app.js 当前项目主页面(外层壳子)</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|----xxx.js</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|--store REDUX这一套</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|</span>
</div><div class="hljs-line"> *  <span class="hljs-string">|--index.js</span>
</div><div class="hljs-line"> */
</div></code></pre>

<p><code>&lt;Switch&gt;</code></p>



<pre class="prettyprint hljs-light"><code class="hljs xml"><div class="hljs-line">/*
</div><div class="hljs-line"> * Switch：REACT-ROUTER中提供的一个组件，这个组件是用来约束路由的（只要有一个ROUTE的PATH被匹配到，直接渲染对应的组件，后面不管是否还能被匹配到，都不在继续渲染了，类似于SWITCH CASE中的机制）
</div><div class="hljs-line"> *
</div><div class="hljs-line"> * 真实项目中，我们一般都会在ROUTE的外面包一层SWITCH，因为加入它之后我们可以做一些处理：
</div><div class="hljs-line"> * <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>&gt;</span>
</div><div class="hljs-line">       <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Home}/</span>&gt;</span>
</div><div class="hljs-line">       <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/custom"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Custom}/</span>&gt;</span>
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">       <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">render</span>=<span class="hljs-string">{()</span> =&gt;</span> {
</div><div class="hljs-line">           return <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>HELLO WORLD<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>;
</div><div class="hljs-line">       }}/&gt;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">       {/*REDIRECT：重定向，重新定向到一个新的地址*/}
</div><div class="hljs-line">       <span class="hljs-tag">&lt;<span class="hljs-name">Redirect</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>/&gt;</span>
</div><div class="hljs-line">   <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span>
</div><div class="hljs-line">* 如果请求的地址和上面两个PATH都不匹配，则执行最后一个ROUTE（ROUTE不设置PATH，所有的路径都可以匹配），如果上面有匹配的，SWITCH会中断下面的匹配的操作（也就是下面都不在执行了）
</div><div class="hljs-line">*/
</div></code></pre>

<p><code>&lt;Link&gt; VS &lt;NavLink&gt;</code></p>



<pre class="prettyprint hljs-light"><code class="hljs xquery"><div class="hljs-line">/*
</div><div class="hljs-line"> * Link VS NavLink
</div><div class="hljs-line"> *   都是ROUTER提供的组件，用来实现组件切换的
</div><div class="hljs-line"> *
</div><div class="hljs-line"> * [Link]
</div><div class="hljs-line"> *   类似于普通的A标签，通过Link中的<span class="hljs-keyword">to</span>可以跳转到具体的路由页面
</div><div class="hljs-line"> *   <span class="hljs-keyword">to</span>=<span class="hljs-string">'/'</span>
</div><div class="hljs-line"> *   <span class="hljs-keyword">to</span>={{
</div><div class="hljs-line"> *      pathname:<span class="hljs-string">'/'</span>,
</div><div class="hljs-line"> *      search:<span class="hljs-string">'?xxx=xxx'</span>,
</div><div class="hljs-line"> *      hash:<span class="hljs-string">'#xxx'</span>
</div><div class="hljs-line"> *   }}
</div><div class="hljs-line"> *
</div><div class="hljs-line"> * [NavLink]
</div><div class="hljs-line"> *   拥有和Link相同的语法和效果，只是在Link的基础上，可以设置一些样式规则
</div><div class="hljs-line"> *   <span class="hljs-number">1</span>、基于NavLink实现跳转，会给点击的元素增加一个active的样式类
</div><div class="hljs-line"> *   <span class="hljs-number">2</span>、我们可以基于activeClassName / activeStyle 重新设置样式(或者样式类)
</div><div class="hljs-line"> *   <span class="hljs-number">3</span>、当路由切换完成，会拿当前的HASH路径和对应的地址做匹配，把匹配到的NavLink设置对应的选中样式（和Route中的PARH路径匹配一样，对于<span class="hljs-string">'/'</span>这种路径我们最好设置exact属性，精准匹配）
</div><div class="hljs-line"> */
</div></code></pre>

<p><code>history / location / match</code></p>



<pre class="prettyprint hljs-light"><code class="hljs pf"><div class="hljs-line">/*
</div><div class="hljs-line"> * 凡是基于ROUTE路由渲染的组件，都会默认被设置三个属性
</div><div class="hljs-line"> *   基于路由渲染：<span class="hljs-variable">&lt;Route path='xxx' component={xxx}&gt;</span>
</div><div class="hljs-line"> *   获取三个属性：this.props
</div><div class="hljs-line"> *
</div><div class="hljs-line"> * history
</div><div class="hljs-line"> *   push：向HISTORY STACK中新增一条记录（跳转到指定的新页面）
</div><div class="hljs-line"> *   goBack：返回上一条记录对应的页面
</div><div class="hljs-line"> *   goForward：前进到下一条记录对应的页面
</div><div class="hljs-line"> *   location：{pathname\search\<span class="hljs-keyword">state</span>\hash} 存储当前页面的一些地址信息
</div><div class="hljs-line"> *   ...
</div><div class="hljs-line"> *
</div><div class="hljs-line"> * location 存储当前页面中的一些信息
</div><div class="hljs-line"> *   pathname
</div><div class="hljs-line"> *   search
</div><div class="hljs-line"> *   hash
</div><div class="hljs-line"> *   <span class="hljs-keyword">state</span>
</div><div class="hljs-line"> *
</div><div class="hljs-line"> * <span class="hljs-built_in">match</span>  存储了每一个路由Route匹配的一些信息
</div><div class="hljs-line"> *   isExact
</div><div class="hljs-line"> *   params
</div><div class="hljs-line"> */
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">实现页面跳转，并且传递一些信息值，有三种方式：
</div><div class="hljs-line"><span class="hljs-number">1</span>. 问号传参
</div><div class="hljs-line">    history.push(`/custom/detail?id=${id}`);  
</div><div class="hljs-line">    详情页面通过this.props.localtion.serach获取
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-number">2</span>. 路径参数
</div><div class="hljs-line">   history.push(`/custom/detail/${id}`);
</div><div class="hljs-line">   路由配置：<span class="hljs-variable">&lt;Route path='/custom/detail/:id?' component={CustomDetail}/&gt;</span>
</div><div class="hljs-line">   详情页面：this.props.<span class="hljs-built_in">match</span>.params获取
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-number">3</span>. Link传参
</div><div class="hljs-line">   <span class="hljs-variable">&lt;Link to={{</span>
</div><div class="hljs-line"><span class="hljs-variable">              pathname: `/custom/detail`,</span>
</div><div class="hljs-line"><span class="hljs-variable">              state: {id: id}</span>
</div><div class="hljs-line"><span class="hljs-variable">          }}/&gt;</span>
</div><div class="hljs-line">   详情页面：this.props.location.<span class="hljs-keyword">state</span>获取
</div><div class="hljs-line">   弊端：一旦页面刷新，信息就丢失了，无法基于STATE获取
</div></code></pre>

<p><code>&lt;WithRouter&gt;</code></p>



<pre class="prettyprint hljs-light"><code class="hljs pf"><div class="hljs-line">export <span class="hljs-keyword">default</span> withRouter(connect(<span class="hljs-keyword">state</span> =&gt; ({...<span class="hljs-keyword">state</span>.custom}), action.custom)(Nav));
</div></code></pre></div></body></html>